package modele;

import java.awt.Color;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.Vector;

/**
 * La classe Polygone représente un vecteur de point grâce à un attribut Vector et 
 * un boolean nous permettant de tester la condition Polygone fermé ou ouvert :<br>
 * <ul>
 * <li>lesPoints</li>
 * <li>is_closed</li>
 * </ul>
 * @author LEPAGE
 *
 */

public class Polygone extends FormeGeometrique implements Serializable {
    /**
     * Notre liste vector implante une structure de tableau dynamique, 
     * c'est-à-dire dont la taille peut s'accroître (ou diminuer) en fonction des besoins.
     * Ici cette structure va prendre en compte des objets Points
     */
	private Vector<Point> lesPoints;
	
	/**
	 * Boolean nous permettant de savoir si le polygone est fermé ou non
	 */
	private boolean is_closed = true;

	/**
	 * Constructeur par défault permettant d'initialiser une liste dynamique de vecteur de points
	 */
	public Polygone() {
		this.lesPoints = new Vector<Point>();
	}

	/**
	 * Constructeur canonique qui prend un vector de points et un boolean en argument
	 * @param argument
	 * @param statusclosed
	 */
	public Polygone(Vector<Point> argument, boolean statusclosed) {
		this.lesPoints = argument;
		this.is_closed = statusclosed;
	}
    /**
     * Constructeur qui prend en paramétre une liste (Vector) de points, un boolean et un objet couleur
     * @param argument
     * @param statusclosed
     * @param c
     */
	public Polygone(Vector<Point> argument, boolean statusclosed, Color c) {
		this.lesPoints = argument;
		this.is_closed = statusclosed;
		this.couleur = c;
	}
	
	/**
	 * Getters qui permet de retourner nos objets points appartenant à notre liste Vector
	 * @return les objets points appartenant à la liste Vector
	 */
	public Vector<Point> getListPoints() {
		return lesPoints;
	}
	/**
	 * Retourne l'état fermé ou non de notre polygone
	 * @return l'état false (Ouvert) ou False (Fermée)
	 */
	public boolean getClosed(){
		return this.is_closed;
	}
    /**
     * Retourne le nombre d'objets Points appartenant au Vector. 
     * @return le nombre de composants Points sous la forme d'un entier
     */
	public int getSize() {
		int size = lesPoints.size();
		return size;
	}

	/**
	 * M'est à jour les objets Points à notre liste Vector
	 * @param listPoints
	 */
	public void setListPoints(Vector<Point> listPoints) {
		this.lesPoints = listPoints;
	}
	/**
	 * M'est à jour l'état du boolean is_closed en prenant comme paramètre false ou true
	 * @param valeur 
	 */
	public void setClosed(boolean valeur){
		this.is_closed=valeur;
	}
    /**
     * Ajoute un élement Point à la fin de notre liste Vecteur de Points
     * le paramètre sujet prend en compte un nouveau Point afin de l'ajouter à cette liste de vecteur de points.
     * @param sujet
     */
	public void addPoint(Point sujet) {
		this.lesPoints.addElement(sujet.createClone());
	}
   /**
    * Supprime un élèment Point de notre liste de vecteur de Points
    * Paramètre sujet étant le Points à supprimer
    * @param sujet
    */
	public void removePoint(Point sujet) {
		this.lesPoints.removeElement(sujet);
	}
    
	/**
	 * Affiche des informations sur l'état de notre polygone, c'est à dire :
	 * Ouvert ou fermé (is_closed)
	 * Le nombre éléments de la liste Vector
	 * @return l'état du Polygone sous forme de chaine de caractère
	 */
	public String toString() {
		String rapport = new String("---------------------------------------------------------\n");
		rapport += "toString du Polygone : ";
		if (this.is_closed) {rapport+="Ce Polygone est fermé, il est composé de "+this.lesPoints.size()+" point(s) :\n";}
		else {rapport+="(Ce Polygone est ouvert)\n";}
				
		Enumeration<Point> e1 = this.lesPoints.elements();
		while (e1.hasMoreElements()) {
			rapport += e1.nextElement().toString() + " \n ";
		}
		rapport += "---------------------------------------------------------";
		return rapport;
	}
	
    /**
     * Test la taille de deux Polygone et si la taille est égal alors on parcourt les deux Polygones
     * et ont les comparent point à point.
     * on peut mettre qu'un seul hasMoreElements car les deux énumérations ont la meme taille.
     * p Prend en paramètre un Polygone
     * @param p 
     * @return un boolean de type false ou true spécifiant si les deux formes géométriques comparées sont égales ou différentes.
     * 
     */
	public boolean equals(FormeGeometrique p) {
		boolean egal = true;
		Enumeration<Point> e1 = this.lesPoints.elements();
		Enumeration<Point> e2 = ((Polygone) p).lesPoints.elements();

		if (this.lesPoints.size() != ((Polygone) p).lesPoints.size())
			return false;
		else {
			while (e1.hasMoreElements() && egal)
			{
				Point p1 = e1.nextElement();
				Point p2 = e2.nextElement();

				egal = p1.equals(p2);
			}
			return egal;
		}
	}

	/**
	 * Crée une copine du polygone passé en paramètre en lui ajoutant le même nombre élèments Points
	 * @return une copie (clone) du polygone passé paramètre
	 */
	@Override
	public Polygone createClone() {
		Polygone res = new Polygone();
		Enumeration<Point> e = lesPoints.elements();
		while (e.hasMoreElements()) {
			res.addPoint(e.nextElement().createClone());
		}
		res.setCouleur(this.couleur);
		return res;
	}
    /**
     * Permet de crée une symétrie du Polygone par rapport à l'origne, c'est à dire par rapport
     * aux coordonnées du Point (X,Y) : (0,0).
     * @param origine étant le point d'abcisse X=0 et Y=0.
     * @return la symétrie du Polygone par rapport à l'origine de coordonnée (X,Y) : (0,0)
     */
	@Override
	public Polygone createSymetrieO(Point origine) {
		Polygone res = new Polygone();
		res.setCouleur(this.couleur);
		Enumeration<Point> e = lesPoints.elements();
		while (e.hasMoreElements()) {
			res.addPoint(e.nextElement().createSymetrieO(origine));
		}
		return res;
	}
	/**
	 * Crée la symétrie du Polygone par rapport à l'abscisse X
	 * @param origine
	 */
	@Override
	public Polygone createSymetrieX(Point origine) {
		Polygone res = new Polygone();
		res.setCouleur(this.couleur);
		Enumeration<Point> e = lesPoints.elements();
		while (e.hasMoreElements()) {
			res.addPoint(e.nextElement().createSymetrieX(origine));
		}
		return res;
	}
	
	@Override
	public Polygone createSymetrieY(Point origine) {
		Polygone res = new Polygone();
		res.setCouleur(this.couleur);
		Enumeration<Point> e = lesPoints.elements();
		while (e.hasMoreElements()) {
			res.addPoint(e.nextElement().createSymetrieY(origine));
		}
		return res;
	}
	
	
	
	/**
	 * 
	 */
	@Override
	//Le perimetre est calculé seulement si le Polygone est fermé et si il a + de 2 Points
	public double perimetre() {
		double perim = 0;
		if (this.is_closed == true && lesPoints.size() > 2) {
			
			int i=0;
			while (i<lesPoints.size()) {
				if(i == lesPoints.size()-1)
				{perim = perim + lesPoints.elementAt(i).distance(lesPoints.elementAt(0));}
				else
				{perim = perim + lesPoints.elementAt(i).distance(lesPoints.elementAt(i+1));}
				i++;
			}
		}
		return perim;
	}


	@Override
	public double surface() {
		return 0;
	}

	
	/**
	 * 
	 */
	@Override
	public void symetrieO(Point origine) {
		Enumeration<Point> e = lesPoints.elements();
		while (e.hasMoreElements()) {
			e.nextElement().symetrieO(origine);
		}
	}

	@Override
	public void symetrieX(Point origine) {
		Enumeration<Point> e = lesPoints.elements();
		while (e.hasMoreElements()) {
			e.nextElement().symetrieX(origine);
		}

	}

	@Override
	public void symetrieY(Point origine) {
		Enumeration<Point> e = lesPoints.elements();
		while (e.hasMoreElements()) {
			e.nextElement().symetrieY(origine);
		}

	}

	
	public LinkedList<Segment> getSegments(){
		LinkedList<Segment> lesSegments = new LinkedList<Segment>();
			
			int i=0;
			while (i<lesPoints.size()) {
				if(i == lesPoints.size()-1)
				{lesSegments.add(new Segment(lesPoints.elementAt(i),lesPoints.elementAt(0)));}
				else
				{lesSegments.add(new Segment(lesPoints.elementAt(i),lesPoints.elementAt(i+1)));}
				i++;
			}
		
		return lesSegments;
		
	}
/**
 * 
 */
	@Override
	public void deplacer(Point depart, Point destination) {
		Enumeration<Point> e = lesPoints.elements();
		while (e.hasMoreElements()) {
			e.nextElement().deplacer(depart, destination);
		}
		
	}
/*
 */
	@Override
	public boolean isOnTheClick(Point clic) {
		for (Segment item : this.getSegments()) {
			if (item.isOnTheClick(clic)) {return true;}
		}
		return false;
	}

}
